package com.main.mainpro.system.controller;

import com.main.mainpro.system.common.SpringBeanUtil;
import com.main.mainpro.system.service.SystemService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author Administrator
 */
@Controller
@RequestMapping("/system")
public class SystemController {

    private static final Logger logger = LoggerFactory.getLogger(SystemController.class);

    @Autowired
    private SystemService systemService;

    /**
     * 在微服务启动后重新注册bean
     */
    @RequestMapping("/reload")
    @ResponseBody
    public void reload(HttpServletRequest request) throws Exception {
        ApplicationContext applicationContext = SpringBeanUtil.getApplicationContext();
        ConfigurableApplicationContext context = (ConfigurableApplicationContext)applicationContext;
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)context.getBeanFactory();
        ClassLoader beanClassLoader = beanFactory.getBeanClassLoader();
        List<Class<?>> clazzs = SpringBeanUtil.loadClass(systemService.getFileByDbJars(systemService.uploadJar(), request), beanClassLoader, null);
        // 先注册bean
        for(Class<?> clazz: clazzs){
            // 已注册的则跳出
            if(beanFactory.containsBean(clazz.getSimpleName())){
                continue;
            }
            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
            beanFactory.registerBeanDefinition(clazz.getSimpleName(), beanDefinitionBuilder.getRawBeanDefinition());
            logger.info("Bean ["+clazz.getSimpleName()+"]: register success");
        }

        // 再注册controller
        for(Class<?> clazz: clazzs){
            if(SpringBeanUtil.hasAnnotation(clazz, Controller.class)){
                SpringBeanUtil.registerController(clazz.getSimpleName());
                logger.info("Controller ["+clazz.getSimpleName()+"]: register success");
            }
        }
    }

    /**
     * 获取服务中所有的controller类
     */
    @RequestMapping("/getController")
    @ResponseBody
    public String[] getController() throws Exception {
        String[] controllers = SpringBeanUtil.controllers(Controller.class);
        return controllers;
    }

    /**
     * 获取所有注册的urlmapping
     * @return
     */
    @RequestMapping("/getAllUrl")
    @ResponseBody
    public List<String> getAllUrl(){
        RequestMappingHandlerMapping mapping = SpringBeanUtil.getApplicationContext().getBean(RequestMappingHandlerMapping.class);
        //获取url与类和方法的对应信息
        Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
        List<String> urlList = new ArrayList<>();
        for (RequestMappingInfo info : map.keySet()){
            //获取url的Set集合，一个方法可能对应多个url
            Set<String> patterns = info.getPatternsCondition().getPatterns();
            for (String url : patterns){
                urlList.add(url);
            }
        }
        return urlList;
    }

    /**
     *
     * @return
     */
    @RequestMapping("/unload")
    @ResponseBody
    public String unLoadJar(HttpServletRequest request) throws IllegalAccessException, InstantiationException, IOException {
        ApplicationContext applicationContext = SpringBeanUtil.getApplicationContext();
        ConfigurableApplicationContext context = (ConfigurableApplicationContext)applicationContext;
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)context.getBeanFactory();
        ClassLoader beanClassLoader = beanFactory.getBeanClassLoader();
        List<Class<?>> clazzs = SpringBeanUtil.loadClass(systemService.getFileByDbJars(systemService.uploadJar(), request), beanClassLoader, "testmodule.jar");
        // 卸载controller
        for(Class<?> clazz: clazzs){
            if(SpringBeanUtil.hasAnnotation(clazz, Controller.class)){
                SpringBeanUtil.unregisterController(clazz.getSimpleName());
            }
            logger.info("Controller ["+clazz.getSimpleName()+"]: unload success");
        }
        for(Class<?> clazz: clazzs){
            // 已注册的卸载
            if(beanFactory.containsBean(clazz.getSimpleName())){
                beanFactory.removeBeanDefinition(clazz.getSimpleName());
                logger.info("Bean ["+clazz.getSimpleName()+"]: unload success");
            }
        }
        URLClassLoader classLoader = (URLClassLoader) beanClassLoader;
        classLoader.close();
        logger.info("classLoader close success");
        System.gc();
        return "卸载成功";
    }

    /**
     *
     * @return
     */
    @RequestMapping("/Test")
    @ResponseBody
    public String Test(HttpServletRequest request) {
        String dbtype = request.getParameter("type");
        if("1".equals(dbtype)){
            return systemService.getDBtest();
        } else {
            return systemService.getDBtest2();
        }
    }

    /**
     * upload
     * @return
     */
    @RequestMapping("/upload")
    public String upload(Map<String, Object> paramMap) {
        paramMap.put("name", "张三");
        paramMap.put("age", 35);
        return "upload";
    }

    /**
     * upload
     * @return
     */
    @RequestMapping("/fileupload")
    @ResponseBody
    public String fileupload(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {
        systemService.saveFile(file);
        return "文件上传成功！";
    }
}
